package com.elitesland.system.service.impl;

import com.elitesland.core.base.BaseModel;
import com.elitesland.system.convert.SysRoleConvert;
import com.elitesland.system.convert.SysUserConvert;
import com.elitesland.system.entity.*;
import com.elitesland.system.repo.SysUserRoleRepo;
import com.elitesland.system.service.SysUserRoleService;
import com.elitesland.system.vo.SysRoleVO;
import com.elitesland.system.vo.SysUserVO;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <pre>
 *     用户角色关联查询实现
 * </pre>
 *
 * @author mir
 * @date 2020-09-28
 */
@Service
public class SysUserRoleServiceImpl implements SysUserRoleService {

    private JPAQueryFactory jpaQueryFactory;

    private SysUserRoleRepo sysUserRoleRepo;

    @Autowired
    public void setJpaQueryFactory(JPAQueryFactory jpaQueryFactory) {
        this.jpaQueryFactory = jpaQueryFactory;
    }

    @Autowired
    public void setSysUserRoleRepo(SysUserRoleRepo sysUserRoleRepo) {
        this.sysUserRoleRepo = sysUserRoleRepo;
    }

    private final QSysUserRoleDO userRoles = QSysUserRoleDO.sysUserRoleDO;

    private final QSysUserDO users = QSysUserDO.sysUserDO;

    private final QSysRoleDO roles = QSysRoleDO.sysRoleDO;

    @Override
    public Set<SysUserVO> listUsersByRoleId(Long roleId) {
        return jpaQueryFactory.select(users)
                .from(users)
                .leftJoin(userRoles).on(userRoles.userId.eq(users.id))
                .where(userRoles.roleId.eq(roleId))
                .fetch()
                .stream().map(SysUserConvert.INSTANCE::doToVo)
                .collect(Collectors.toSet());
    }

    @Override
    public Map<Long, Set<SysUserVO>> listUsersByRoleIds(List<Long> roleIds) {
        val roleUserTuples = jpaQueryFactory.select(
                userRoles.roleId,
                users
        ).from(users)
                .leftJoin(userRoles).on(userRoles.userId.eq(users.id))
                .where(userRoles.roleId.in(roleIds)).fetch();

        return roleUserTuples.stream().collect(
                Collectors.groupingBy(
                        t -> t.get(0, Long.class),
                        Collectors.mapping(
                                t -> SysUserConvert.INSTANCE.doToVo(t.get(1, SysUserDO.class)),
                                Collectors.toSet()
                        )
                )
        );
    }

    @Override
    public Set<SysRoleVO> listRolesByUserId(Long userId) {
        return jpaQueryFactory.select(roles)
                .from(roles)
                .leftJoin(userRoles).on(userRoles.roleId.eq(roles.id))
                .where(userRoles.userId.eq(userId))
                .fetch()
                .stream().map(SysRoleConvert.INSTANCE::doToVo)
                .collect(Collectors.toSet());
    }

    @Override
    public Map<Long, Set<SysRoleVO>> listRolesByUserIds(List<Long> userIds) {
        val userRoleTuples = jpaQueryFactory.select(
                userRoles.userId,
                roles
        ).from(roles)
                .leftJoin(userRoles).on(userRoles.roleId.eq(roles.id))
                .where(userRoles.userId.in(userIds)).fetch();

        return userRoleTuples.stream().collect(
                Collectors.groupingBy(
                        t -> t.get(0, Long.class),
                        Collectors.mapping(
                                t -> SysRoleConvert.INSTANCE.doToVo(t.get(1, SysRoleDO.class)),
                                Collectors.toSet()
                        )
                )
        );
    }

    @Override
    public void saveAll(List<SysUserRoleDO> userRoles) {
        val ids = userRoles.stream().filter(ur -> ur.getId() != null && ur.getId() > 0)
                .map(BaseModel::getId)
                .collect(Collectors.toList());
        if (!ids.isEmpty()) {
            sysUserRoleRepo.deleteAllByIdIn(ids);
        }
        sysUserRoleRepo.saveAll(userRoles);
    }

    @Override
    public void removeUsersByRoleIds(List<Long> roleIds) {
        sysUserRoleRepo.deleteAllByRoleIdIn(roleIds);
    }

    @Override
    public void removeRolesByUserIds(List<Long> userIds) {
        sysUserRoleRepo.deleteAllByUserIdIn(userIds);
    }

}
